package cn.jh.common.core.io;

import com.google.common.collect.ImmutableList;

import java.util.List;

/**
 * {@code java.io.Externalizable} 接口的工具。
 *
 * @author Fuchun
 * @since 1.0
 */
public class ExternalizableKt {

    private static final List<Integer> INT_BIT_MASKS;
    private static final List<Long> LONG_BIT_MASKS;

    static {
        ImmutableList.Builder<Integer> bi = ImmutableList.builder();
        ImmutableList.Builder<Long> bl = ImmutableList.builder();
        int bitIndex = 0;
        long longBitMask;
        for (int i = 0; i < 63; i++) {
            longBitMask = 1L << bitIndex++;
            if (i < 31) {
                bi.add((int) longBitMask);
            }
            bl.add(longBitMask);
        }
        INT_BIT_MASKS = bi.build();
        LONG_BIT_MASKS = bl.build();
    }

    public static int intBitMask(int index) {
        int size = INT_BIT_MASKS.size();
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("The index out of bounds for int bit mask.");
        }
        return INT_BIT_MASKS.get(index);
    }

    public static long longBitMask(int index) {
        int size = LONG_BIT_MASKS.size();
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("The index out of bounds for long bit mask.");
        }
        return LONG_BIT_MASKS.get(index);
    }

    /**
     * Returns {@code true} if the given {@code bitMask} argument indicates that the specified field has been
     * serialized and therefore should be read during deserialization, {@code false} otherwise.
     *
     * @param bitMask      the aggregate bitmask for all fields that have been serialized.  Individual bits represent
     *                     the fields that have been serialized.  A bit set to 1 means that corresponding field has
     *                     been serialized, 0 means it hasn't been serialized.
     * @param fieldBitMask the field bit mask constant identifying which bit to inspect (corresponds to a class attribute).
     * @return {@code true} if the given {@code bitMask} argument indicates that the specified field has been
     * serialized and therefore should be read during deserialization, {@code false} otherwise.
     */
    public static boolean isFieldPresent(int bitMask, int fieldBitMask) {
        return (bitMask & fieldBitMask) != 0;
    }
}
